/*
 * Copyright (c) 2023. bmy
 * Email：2271608011@qq.com
 * Github：https://github.com/helpcode
 */

import { ConfigureConfig } from "@config/configure.config";
import AxioDao from "@dao/index.dao";
import { JsontoClass, JsontoClasses } from "@ann/JsonToClass";


interface ParamsType {
  url?: string;
  useHandle?: boolean;
  header?: { [key: string]: any };
}

/**
 * 将 接口返回 数据所对应的 类，在类的方法上定义元数据，key为mapper，值为 传入的 type
 * @param type 
 * @returns 
 */
export function Mapper(type: { new(...args: any[]): any }) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    Reflect.defineMetadata('mapper', type, target, propertyKey);
  }
}

/**
 * GET 请求注解
 * @param RequestParams
 * @constructor
 */
export function GET(RequestParams?: ParamsType) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    CheckParams('get', target, propertyKey, descriptor, <ParamsType>RequestParams)
  }
}

/**
 * POST 请求注解
 * @param RequestParams
 * @constructor
 */
export function POST(RequestParams?: ParamsType) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    CheckParams('post', target, propertyKey, descriptor, <ParamsType>RequestParams)
  }
}

/**
 * PUT 请求注解
 * @param RequestParams
 * @constructor
 */
export function PUT(RequestParams?: ParamsType) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    CheckParams('put', target, propertyKey, descriptor, <ParamsType>RequestParams)
  }
}

/**
 * DELETE 请求注解
 * @param RequestParams
 * @constructor
 */
export function DELETE(RequestParams?: ParamsType) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    CheckParams('delete', target, propertyKey, descriptor, <ParamsType>RequestParams)
  }
}



// GET POST PUT DELETE 四个装饰器最终 都会走这里代码进行发送请求
// 所以 在 http.annotation.ts 文件中 引入插件 json-class-interface
// 调 json-class-interface 的方法 来配置 生成的 class 存放路径 为 /service/type 文件夹
// 请求完成后 先使用 装饰器 的 target.name+_+propertyKey 作为文件名并 在路径下生成空的 .ts 文件
// 然后调用 json-class-interface 的 toClass 方法传入propertyKey作为第一层类的名称
// 并传入 res 请求到的json数据，得到最终的 类代码，然后让 json-class-interface 将 类代码 写入刚生成的 .ts 文件中


// 唯一需要开发者手动做的事情如下，举例：
// User.service.impl.ts 中 的 xxx 方法 GET 装饰器 传入 刚生成文件中的 propertyKey 类名
// 这里的代码会自动调用 插件 json-mapper-class 进行 JsontoClasses 或者 JsontoClass 进行序列化

// 伪代码
// configTypePath("service/type")
// wirteFileType(`${target.name_propertyKey}.ts`, toClass(propertyKey,res) )

// 
function CheckParams(
  methods: "get" | "post" | "put" | "delete",
  target: any, propertyKey: string,
  descriptor: PropertyDescriptor,
  Params: ParamsType) {

  Params == undefined ? Params = {} : null;
  Params.url = Params.url || ConfigureConfig.AjaxConfig.ApiList[propertyKey]
  Params.useHandle = Params.useHandle || false
  Params.header = Params.header || {}
  let MapperClass = Reflect.getMetadata('mapper', target, propertyKey);
  
  if (MapperClass) {
    let OldMethods = descriptor.value;
    descriptor.value = async (data: { [key: string]: any }) => {
      let res = await AxioDao[methods]({
        url: <string>Params.url, data,
        headers: Params.header
      });
      res = res instanceof Array ? JsontoClasses(res, MapperClass) : JsontoClass(res, MapperClass)
      if (Params.useHandle) {
        return await OldMethods.call(target, res)
      } else {
        return res
      }
    }
  }

}
